<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>

  <body>
    <!-- 调度所有战士的共性 -->
    <button id="btn1">敌方大兵压境</button>

    <!-- 司徒王朗来了，调度个性：派出诸葛村夫 -->
    <button id="btn2">王司徒来了</button>

    <script>
      /* 封装战士父类 */
      function Fighter(name) {
        this.name = name;
      }
      // 凡战士 必会战斗
      Fighter.prototype.fight = function () {
        console.log(`${this.name}开始战斗`);
      };
      //   const mks = new Fighter("马克思");
      //   mks.fight(); //fight中的this即为mks
    </script>

    <!-- 封装Fighter的不同子类 -->
    <!-- 法师类 -->
    <script>
      // magic=法师 balabala=咒语
      function Magic(name, balabala) {
        // 通过调用父类的构造方法+绑定this继承属性
        Fighter.call(this, name);
        this.balabala = balabala;
      }
      // 继承父类方法：娶一个父类实例做子类的原型
      Magic.prototype = new Fighter();

      // 父类的战斗方法我不满意——重写之，覆盖之 override
      Magic.prototype.fight = function () {
        // 父类的战斗方法有可取之初 先拿来调用 提前绑定主语this为当前的
        Fighter.prototype.fight.call(this);

        // 扩展一些新的东西
        console.log(`${this.name}:${this.balabala}！`);
      };

      //   const zgcf = new Magic("诸葛村夫");
      //   // 当原型链的多级都有fight方法时 就近取用原则
      //   zgcf.fight(); //fight中的this即zgcf
    </script>

    <!-- 弓箭手类 -->
    <script>
      // archer=弓箭手 bullet=子弹
      function Archer(name, bullet) {
        // 通过调用父类的构造方法+绑定this继承属性
        Fighter.call(this, name);

        this.bullet = bullet;
      }
      // 继承父类方法：娶一个父类实例做子类的原型
      Archer.prototype = new Fighter();

      // 父类的战斗方法我不满意——重写之，覆盖之 override
      Archer.prototype.fight = function () {
        // 父类的战斗方法有可取之初 先拿来调用 提前绑定主语this为当前的
        Fighter.prototype.fight.call(this);

        // 扩展一些新的东西
        console.log(`${this.name}:口吐${this.bullet}`);
      };

      //   const wdss = new Archer("豌豆射手", "大豌豆");
      //   // 当原型链的多级都有fight方法时 就近取用原则
      //   wdss.fight(); //fight中的this即zgcf
    </script>

    <!-- 骑兵 -->
    <script>
      // kngight=骑士 weapon=武器
      function Knight(name, weapon) {
        // 通过调用父类的构造方法+绑定this继承属性
        Fighter.call(this, name);

        this.weapon = weapon;
      }
      // 继承父类方法：娶一个父类实例做子类的原型
      Knight.prototype = new Fighter();

      // 父类的战斗方法我不满意——重写之，覆盖之 override
      Knight.prototype.fight = function () {
        // 父类的战斗方法有可取之初 先拿来调用 提前绑定主语this为当前的
        Fighter.prototype.fight.call(this);

        // 扩展一些新的东西
        console.log(`${this.name}:挥舞ta的${this.weapon}呼啸而上`);
      };

      //   const gy = new Knight("关羽", "青龙偃月刀");
      //   // 当原型链的多级都有fight方法时 就近取用原则
      //   gy.fight(); //fight中的this即zgcf
    </script>

    <!-- 业务逻辑 -->
    <script>
      // 造法师 骑士 弓箭手各一个
      const zgcf = new Magic("诸葛村夫", "我从未见过如此厚颜无耻之人！");
      const qybf = new Magic(
        "奇异博士",
        "i've never seen such a shameless guy!"
      );
      const gy = new Knight("关羽", "青龙偃月刀");
      const wdss = new Archer("豌豆射手", "大豌豆");

      // 组建一支大军
      const fighters = [zgcf, qybf, gy, wdss];

      // 敌人大兵压境时 需要的是共性 大家一起战斗
      btn1.onclick = function (e) {
        // 调度所有战士的共性
        fighters.forEach((f) => f.fight());
      };

      // 王司徒来了 需要的是个性
      // 毫不犹豫地派出大法师诸葛村夫
      btn2.onclick = function (e) {
        // 找出所有法师 一起进攻
        const magics = fighters.filter(
          // 战士进去 该战士是否superok出来
          // obj instanceof A 判断obj是否是A类的实例,运算结果是布尔值
          (f) => f instanceof Magic
        );

        // 所有的法师一起上
        magics.forEach((m) => m.fight());
      };
    </script>
  </body>
</html>
